package cloud.maque.admin.impl;

import cloud.maque.admin.domain.consts.ConstVar;
import cloud.maque.admin.domain.entity.MqMenu;
import cloud.maque.admin.domain.entity.MqUser;
import cloud.maque.admin.domain.request.MenuRoleRequest;
import cloud.maque.admin.domain.vo.MenuDetailVo;
import cloud.maque.admin.domain.vo.MenuVo;
import cloud.maque.admin.mapper.MqMenuMapper;
import cloud.maque.admin.service.MqMenuPrivilegeService;
import cloud.maque.admin.service.MqMenuService;
import cloud.maque.admin.service.MqRolePrivilegeService;
import cloud.maque.admin.service.MqUserService;
import cloud.maque.framework.common.exception.BusinessException;
import cloud.maque.framework.common.request.PaginateDataResquest;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import java.util.stream.Collectors;

/**
 * 菜单实现类
 *
 * @author zhuyf
 * @date 2023/3/17 10:21
 */
@Service
public class MqMenuServiceImpl extends ServiceImpl<MqMenuMapper, MqMenu> implements MqMenuService {


    @Autowired
    MqMenuPrivilegeService mqMenuPrivilegeService;

    @Autowired
    MqRolePrivilegeService rolePrivilegeService;

    @Autowired
    MqPrivilegeServiceImpl privilegeService;

    @Autowired
    MqUserService userService;

    /**
     * 添加菜单时，必须要给菜单添加一个基本权限，然后绑定关系
     *
     * @param mqMenu 记录对象
     * @return
     */
    @Override
    @Transactional
    public MenuDetailVo saveMenu(MenuDetailVo mqMenu) {
        checkMenuValue(mqMenu);

        if (!StrUtil.isEmptyIfStr(mqMenu.getMenuId())) {
            privilegeService.deleteByMenuId(mqMenu.getMenuId());
        }

        Boolean isuccess = this.saveOrUpdate(mqMenu);
        if (isuccess) {
            privilegeService.CreateMenuPrivileleg(mqMenu.getMenuId(), mqMenu.getTenantId());
            //插入角色
            MenuRoleRequest menuRoleRequest = new MenuRoleRequest();
            menuRoleRequest.setMenuId(mqMenu.getMenuId());
            menuRoleRequest.setRoleIds(mqMenu.getRoleIdList());
            rolePrivilegeService.addRoleForMenu(menuRoleRequest);

            saveParentMenuRole(mqMenu.getRoleIdList(), mqMenu.getParentId());
            return mqMenu;
        } else {
            return null;
        }
    }

    /**
     * 把菜单上一级也写入角色
     */
    private void saveParentMenuRole(List<String> roleIdList, String menuParentId) {

        for (String roleId : roleIdList) {
            rolePrivilegeService.deleteByRoleAndMenuId(roleId, menuParentId);
            //插入角色
            rolePrivilegeService.addRoleAndMenu(roleId, menuParentId);

            MqMenu menu = this.getById(menuParentId);
            if (menu != null) {
                saveParentMenuRole(roleIdList, menu.getParentId());
            }
        }

    }

    @Override
    @Transactional
    public Boolean delete(String menuId) {

        //判断是否有下级
        if (countByParent(menuId) > 0) {
            throw new RuntimeException("还有下级菜单,不能删除");
        }

        mqMenuPrivilegeService.DeleteByMenuId(menuId);

        return this.removeById(menuId);
    }

    private Integer countByParent(String menuId) {
        QueryWrapper<MqMenu> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(MqMenu::getParentId, menuId);

        return count(queryWrapper);
    }

    @Override
    public PageInfo<MqMenu> page(PaginateDataResquest<MqMenu> pageReq) {

        PageHelper.startPage(pageReq.getPageIndex(), pageReq.getPageSize());
        QueryWrapper<MqMenu> wrapper = new QueryWrapper<>();

        if (!StrUtil.isEmptyIfStr(pageReq.getData().getMenuName())) {
            wrapper.lambda().like(MqMenu::getMenuName, pageReq.getData().getMenuName());
        }

        if (!StrUtil.isEmptyIfStr(pageReq.getData().getMenuPath())) {
            wrapper.lambda().like(MqMenu::getMenuPath, pageReq.getData().getMenuPath());
        }

        if (!StrUtil.isEmptyIfStr(pageReq.getData().getMenuType())) {
            wrapper.lambda().eq(MqMenu::getMenuType, pageReq.getData().getMenuType());
        }

        if (!StrUtil.isEmptyIfStr(pageReq.getData().getParentId())) {
            wrapper.lambda().eq(MqMenu::getParentId, pageReq.getData().getParentId());
        }


        if (!StrUtil.isEmptyIfStr(pageReq.getData().getTenantId())) {
            wrapper.lambda().eq(MqMenu::getTenantId, pageReq.getData().getTenantId());
        }

        wrapper.lambda().orderByAsc(MqMenu::getMenuOrder);
        wrapper.lambda().orderByAsc(MqMenu::getMenuId);
        List<MqMenu> lists = this.baseMapper.selectList(wrapper);
        PageInfo<MqMenu> pageInfo = new PageInfo<>(lists);

        return pageInfo;
    }


    /**
     * 返回用户的菜单
     *
     * @param userId
     * @return
     */
    @Override
    public List<MenuVo> getUserMenu(String userId) {

        List<MenuVo> allMenu = new ArrayList<>();

        MqUser user = userService.getUser(userId);
        if (user == null) {
            throw new BusinessException("用户不存在");
        }

        List<MqMenu> menuList = new ArrayList<>();

        //如果不是超管租户，则根据套餐获取菜单
        if (!user.getTenantId().equals(ConstVar.ManagerTenandId)) {
            if (user.getIsTenantManager().equals(1)) {
                menuList = this.baseMapper.getUserMenuByTenantCombo(userId, user.getTenantId());
            } else {
                //如果不是租户管理员，只读取角色下面的菜单
                menuList = this.baseMapper.getUserMenu(userId);
            }
        } else {
            //根据角色获取菜单
            menuList = this.baseMapper.getUserMenu(userId);
        }
        //获取第一级的菜单
        menuList.forEach(new Consumer<MqMenu>() {
            @Override
            public void accept(MqMenu mqMenu) {
                if (mqMenu.getParentId().equals("0") || mqMenu.getParentId().equals("")) {
                    MenuVo menuVo = new MenuVo();
                    BeanUtil.copyProperties(mqMenu, menuVo);
                    allMenu.add(menuVo);
                }
            }
        });

        RecursionMenuChildren(menuList, allMenu);

        return allMenu;
    }

    /**
     * 返回菜单树
     *
     * @return
     */
    @Override
    public List<MenuVo> MenuTree(PaginateDataResquest<MqMenu> pageReq, String root) {
        QueryWrapper<MqMenu> queryWrapper = new QueryWrapper<>();

        if (pageReq.getData() != null) {
            if (!StrUtil.isEmptyIfStr(pageReq.getData().getTenantId())) {
                queryWrapper.lambda().eq(MqMenu::getTenantId, pageReq.getData().getTenantId());
            } else {
                queryWrapper.lambda().eq(MqMenu::getTenantId, ConstVar.NoObject);
            }
        } else {
            queryWrapper.lambda().eq(MqMenu::getTenantId, ConstVar.NoObject);
        }
        if (pageReq.getData() != null && pageReq.getData().getMenuId() != null) {
            if (!pageReq.getData().getMenuId().equals("0") && !pageReq.getData().getMenuId().equals("")) {
                queryWrapper.lambda().ne(MqMenu::getMenuId, pageReq.getData().getMenuId());
                queryWrapper.and(q -> {
                    q.lambda().ne(MqMenu::getParentId, pageReq.getData().getMenuId());
                });
            }
        }

        queryWrapper.lambda().orderByAsc(MqMenu::getMenuOrder);

        List<MenuVo> allMenu = new ArrayList<>();
        List<MqMenu> menuList = this.baseMapper.selectList(queryWrapper);
        //获取第一级的菜单
        menuList.forEach(new Consumer<MqMenu>() {
            @Override
            public void accept(MqMenu mqMenu) {
                if (mqMenu.getParentId().equals("0")) {
                    MenuVo menuVo = new MenuVo();
                    BeanUtil.copyProperties(mqMenu, menuVo);
                    menuVo.setDisabled(0);
                    allMenu.add(menuVo);
                }
            }
        });
        RecursionMenuChildren(menuList, allMenu);

        if (root.equals("1")) {
            List<MenuVo> rootMenu = new ArrayList<>();
            MenuVo menuVo = new MenuVo();
            menuVo.setMenuName("根节点");
            menuVo.setParentId("");
            menuVo.setMenuId("0");
            menuVo.setChildren(allMenu);
            rootMenu.add(menuVo);
            return rootMenu;
        } else {
            return allMenu;
        }
    }


    @Override
    public MenuDetailVo getDetail(String menuId, String tenantId) {

        MenuDetailVo vo = new MenuDetailVo();
        vo = vo.convert(getMenuAndTenantId(menuId, tenantId));
        vo.setRoleIdList(mqMenuPrivilegeService.GetRoleIdsByMenuId(menuId));
        return vo;
    }

    private MqMenu getMenuAndTenantId(String menuId, String tenantId) {

        QueryWrapper<MqMenu> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(MqMenu::getMenuId, menuId);
        queryWrapper.lambda().eq(MqMenu::getTenantId, tenantId);
        return this.getOne(queryWrapper);
    }

    private boolean findMenu(List<MqMenu> menuList, String menuId) {
        if (StrUtil.isEmptyIfStr(menuId)) {
            return false;
        }
        Long find = menuList.stream().filter(menu -> menu.getMenuId().equals(menuId)).count();
        return find > 0;
    }

    /**
     * 向下递归查找
     *
     * @param allMenus
     */
    private void RecursionMenuChildren(List<MqMenu> allMenus, List<MenuVo> thisMenus) {

        //递归查找所有下级菜单
        thisMenus.forEach(new Consumer<MenuVo>() {
            @Override
            public void accept(MenuVo menuVo) {
                List<MqMenu> findChild = allMenus.stream().filter(menu -> menu.getParentId().equals(menuVo.getMenuId())).collect(Collectors.toList());
                if (findChild != null && findChild.size() > 0) {
                    List<MenuVo> findChildVo = new ArrayList<>();
                    findChild.forEach(new Consumer<MqMenu>() {
                        @Override
                        public void accept(MqMenu mqMenu) {
                            MenuVo vo = new MenuVo();
                            BeanUtil.copyProperties(mqMenu, vo);
                            menuVo.setDisabled(0);
                            findChildVo.add(vo);
                        }
                    });
                    RecursionMenuChildren(allMenus, findChildVo);
                    menuVo.setChildren(findChildVo);
                }
            }
        });
    }

    private void checkMenuValue(MqMenu mqEnum) {
        Assert.hasText(mqEnum.getMenuName(), "菜单名称不能为空");
        Assert.hasText(mqEnum.getTenantId(), "TenantId不能为空");
        Assert.hasText(mqEnum.getParentId(), "Parentid不能为空");
    }


}

